#include "GPUFaceDetection.h"
#include "support.h"
#include <QDebug>

const std::string GPUFaceDetection::faceCascadeName = "Cascades/HS.xml";
const cv::Size GPUFaceDetection::defMinSize(25, 25);

GPUFaceDetection::GPUFaceDetection(void) : Filter(1,1)
{
	bool r;
	r = gpuFaceCascade.load(faceCascadeName);

	minSize = defMinSize;

	ROI = cv::Rect(0, 0, 640, 480);
}


GPUFaceDetection::~GPUFaceDetection(void)
{
	gpuFaceCascade.release();
}

void GPUFaceDetection::Process()
{
	cv::gpu::GpuMat input0;
	input0.upload(*inputs[0]);
	cv::gpu::GpuMat frameGray;
	//cv::Mat frameGray;
	if (inputs[0]->channels() == 3)
	{
		cv::gpu::cvtColor(input0, frameGray, CV_BGR2GRAY);
	}
	else if (inputs[0]->channels() == 1)
	{
		frameGray = input0;
	}

	cv::gpu::equalizeHist(frameGray, frameGray);

	cv::gpu::GpuMat frameGrayROI = frameGray(ROI);
	cv::gpu::GpuMat buffer;
	int faceDetections = gpuFaceCascade.detectMultiScale(frameGrayROI, buffer, 1.1, 2, minSize);

	cv::Mat faces;

	if (faceDetections == 0)
	{
		buffer = cv::gpu::GpuMat();
		ROI = cv::Rect(cv::Point(0,0), cv::Size(inputs[0]->cols, inputs[0]->rows));
		faceDetections = gpuFaceCascade.detectMultiScale(frameGray, buffer, 1.1, 2, minSize);
	}

	buffer.colRange(0, faceDetections).download(faces);

	if (faceDetections > 0)
	{
		cv::Rect *facePtr = faces.ptr<cv::Rect>(0);
		cv::Rect face = cv::Rect(facePtr->x + ROI.x, facePtr->y + ROI.y, facePtr->width, facePtr->height);
		cv::gpu::GpuMat faceROI = input0(face);
		outputs[0] = cv::Mat(1, 4, CV_32SC1);
		outputs[0].at<int>(0,0) = face.x;
		outputs[0].at<int>(0,1) = face.y;
		outputs[0].at<int>(0,2) = face.width;
		outputs[0].at<int>(0,3) = face.height;

		minSize = cv::Size(face.width * 0.85, face.height * 0.85);

		ROI = cv::Rect(face.x - face.width * 0.75, face.y - face.height * 0.75, face.width * 2.5, face.height * 2.5);
		ROI.x = MAX(0, ROI.x);
		ROI.y = MAX(0, ROI.y);
		if (ROI.x + ROI.width >= inputs[0]->cols)
			ROI.width = inputs[0]->cols - ROI.x - 1;
		if (ROI.y + ROI.height >= inputs[0]->rows)
			ROI.height= inputs[0]->rows - ROI.y - 1;
	} 
	else
	{
		minSize = defMinSize;
		ROI = cv::Rect(cv::Point(0,0), cv::Size(inputs[0]->cols, inputs[0]->rows));
	
		outputs[0] = cv::Scalar_<int>(0);

		outputValid[0] = false;
	}

	
}
